/*
 * parser.c
 *
 * E103的串口解析子任务
 *
 *  Created on: Jan 2, 2022
 *      Author: soliber
 */

//Include
#include "wifi.h"

//Typedef
#pragma pack(push)
#pragma pack(1)
//接收到的一包数据
typedef struct {
	uint8_t header[3];	//固定头 AA FE 55
	uint8_t socket_id;
	uint16_t len;		//数据长度，注意是网络字节序，需要转换为主机字节序
	uint8_t *data;
}recv_pack_t;
#pragma pack(pop)


//Define
#define LOG_TAG "parser"

#define EVT_FLAG_START		(1<<0)	//启动事件
#define EVT_FLAG_CONNECT	(1<<1)	//AP建立连接事件
#define EVT_FLAG_DISCONN	(1<<2)	//AP断开连接事件
#define EVT_FLAG_NOLINK		(1<<3)	//无连接时间

#define DMA_RX_BUF_LEN		64	//接收 DMA Buffer长度
#define FIFO_LEN			1000//FIFO长度
#define SYNC_CHECK_LEN 		32	//同步头检查长度
#define SYNC_CHECK_TIMEOUT	10	//同步头检查间隔
#define SYNC_HEADER "\xAA\xFE\x55"

#define EVT_STRING_START "e103-w08 start\r\n"
#define EVT_STRING_TCP_SINGLE	"tcp single\r\n"
#define EVT_STRING_TCP_MULTY	"tcp multy\r\n"
#define EVT_STRING_NO_LINK		"no link\r\n"
#define EVT_STRING_HEADER_ERROR	"header error\r\n"


//Macro


//Variables
osThreadId_t parserTaskHandle;
const osThreadAttr_t parserTask_attributes = {
  .name = "parserTask",
  .stack_size = 256 * 4,
  .priority = (osPriority_t) osPriorityHigh1,
};
StreamBufferHandle_t parserSB;
osEventFlagsId_t urc;

static uint8_t dma_rx_buf[DMA_RX_BUF_LEN]={};

//Function Prototypes
static void StartParser(void* param);
static void Protocol_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Pos);


/**
 * @brief 解析器初始化
 */
void ParserInit(void)
{
	//创建事件
	urc = osEventFlagsNew(NULL);
	assert(urc != NULL);

	//创建StreamBuffer
	parserSB = xStreamBufferCreate(FIFO_LEN,1);
	assert(parserSB!=NULL);

	//设置串口接收回调
	wifi_uart.RxEventCallback = Protocol_RxEventCallback;

	//创建任务
	parserTaskHandle = osThreadNew(StartParser, NULL, &parserTask_attributes);
	assert(parserTaskHandle != NULL);
}

/**
 * @brief 解析器解初始化
 */
void ParserDeInit(void)
{
	osStatus_t ret;
	//终止串口
	HAL_UART_Abort(&wifi_uart);
	//删除任务
	ret = osThreadTerminate(parserTaskHandle);
	assert(ret == osOK);
	//清串口接收回调
	wifi_uart.RxEventCallback = NULL;
	//删除StreamBuffer
	vStreamBufferDelete(parserSB);
	//删除事件
	ret = osEventFlagsDelete(urc);
	assert(ret == osOK);
}

/**
 * @brief 等待模块启动
 *
 * @param timeout 超时等待时间
 */
void WaitStart(uint32_t timeout)
{
	uint32_t ret = osEventFlagsWait(urc, EVT_FLAG_START, osFlagsWaitAny, timeout);
	assert(ret == EVT_FLAG_START);
}

/**
 * @brief 等待AP连接
 *
 * @param timeout 超时等待时间
 *
 * @return 连接状态
 * @retval 0 连接成功
 * @retval 1 连接超时
 */
int8_t WaitAPConnect(uint32_t timeout)
{
	uint32_t ret = osEventFlagsWait(urc, EVT_FLAG_CONNECT, osFlagsWaitAny, timeout);
	return (ret == EVT_FLAG_CONNECT)?0:1;
}

/**
 * @brief 解析器任务入口
 *
 * @param param
 */
static void StartParser(void* param)
{
	//同步头检查buffer
	char sync[SYNC_CHECK_LEN] = {};

	//buffer中有效数据量
	uint16_t write = 0;

	//开始解析处
	char *parser_begin;

	//从parser_begin开始，在解析过程中消费的数据量
	uint16_t consume = 0;

	//sync在解析过程未消费的数据量
	uint16_t remain = 0;

	//开始DMA接收
	assert(HAL_UARTEx_ReceiveToIdle_DMA(&wifi_uart, dma_rx_buf, sizeof(dma_rx_buf)) == HAL_OK);

	while(1)
	{
		//定时检查同步头
		xStreamBufferSetTriggerLevel(parserSB, SYNC_CHECK_LEN - write);
		write += xStreamBufferReceive(parserSB, sync + write, SYNC_CHECK_LEN - write, 10);
		assert(write<=SYNC_CHECK_LEN);

		//匹配到协议同步头
		if(parser_begin = strnstr(sync,SYNC_HEADER,write))
		{
			//一包数据
			static recv_pack_t pack={};
			//读指针
			char *read = parser_begin;

			//读头部6Byte数据header+id+len
			{
				//sync中数据足够
				if(read+6<=sync+write)
				{
					memcpy(&pack,read,6);
					read+=6;
					consume = 6;
				}
				//sync中数据不足
				else
				{
					//有多少拿多少
					uint16_t sync_remain = sync+write-read;
					if(sync_remain)
					{
						memcpy(&pack,read,sync_remain);
						read+=sync_remain;
					}
					//从sb中拿
					xStreamBufferSetTriggerLevel(parserSB, 6-sync_remain);
					if(xStreamBufferReceive(parserSB, read, 6-sync_remain, 10)!=6-sync_remain)
					{
						log_w("pack header not integrity!");
					}
				}
			}

			if(pack.len)
			{
				//申请内存，存放这包数据
				pack.data = malloc(pack.len);
				assert(pack.data!=NULL);	//内存不足

				//从sync和parserSB中拿数据部分
				{
					//计数
					uint16_t cnt=0;
					//从sync中拿数据
					while(read<sync+write)
					{
						pack.data[cnt]=*read;
						read++;
						cnt++;
					}
					//计算sync中消费的数据量
					consume = read - parser_begin;
					//从parserSB拿数据
					uint8_t try = 3;
					while(cnt<pack.len&&try)
					{
						uint16_t take_from_sb = pack.len - cnt;
						xStreamBufferSetTriggerLevel(parserSB, take_from_sb);
						cnt += xStreamBufferReceive(parserSB, pack.data+cnt, take_from_sb, 100);
						if(--try==0)
						{
							log_w("pack lost, need %d byte but %d byte",pack.len,cnt);
							log_w("parserSB %d",xStreamBufferBytesAvailable(parserSB));
							pack.len = cnt;
							break;
						}
					}
				}

				//数据搬运到socket对应的buffer
				{
					//可用的socket
					wifi_socket_t * sk = get_socket(pack.socket_id);
					if(sk==NULL)
					{
						log_w("socket id out of range:%d",pack.socket_id);
					}
					else if(sk->lock!=NULL)
					{
						//发送到对应socket的fifo中
						pack.len -= xStreamBufferSend(sk->rxBuf,
								pack.data, pack.len, 1000);
						if(pack.len)
						{
							log_w("socket %d data may lost",pack.socket_id);
						}
						HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
					}
					//socket不可用
					else
					{
						log_w("why socket %d is closed?",pack.socket_id);
					}
				}

				//释放内存
				free(pack.data);
			}
			else
			{
				log_w("empty pack?");
			}
		}
		//匹配到启动消息
		else if(parser_begin = strnstr(sync,EVT_STRING_START,write))
		{
			//消费数据
			consume = strlen(EVT_STRING_START);

			//触发事件
			osEventFlagsSet(urc, EVT_FLAG_START);
		}
		//匹配到连接消息:TCP多连接
		else if(parser_begin = strnstr(sync,EVT_STRING_TCP_MULTY,write))
		{
			//消费数据
			consume = strlen(EVT_STRING_TCP_MULTY);

			//触发事件
			osEventFlagsSet(urc, EVT_FLAG_CONNECT);
		}
		//匹配到连接消息:TCP单连接
		else if(parser_begin = strnstr(sync,EVT_STRING_TCP_SINGLE,write))
		{
			//消费数据
			consume = strlen(EVT_STRING_TCP_SINGLE);

			//触发事件
			osEventFlagsSet(urc, EVT_FLAG_CONNECT);
		}
		//匹配到未连接消息
		else if(parser_begin = strnstr(sync,EVT_STRING_NO_LINK,write))
		{
			//消费数据
			consume = strlen(EVT_STRING_NO_LINK);

			//触发事件
			osEventFlagsSet(urc, EVT_FLAG_NOLINK);
		}
		//什么都没匹配到
		else
		{
			//继续匹配，但如果sync已满则需要丢弃
			write = (write<SYNC_CHECK_LEN)?write:0;
			continue;
		}

		//未消费数据移动到开头 TODO 连续数据包无法解析
		remain = (sync+write) - (parser_begin+consume);
		if(remain>0)
		{
			memcpy(sync,parser_begin+consume,remain);
		}
		write = remain;
	}
}


/**
 * @brief 串口接收事件
 *
 * @param huart 串口句柄
 * @param Pos 接收Buffer中可用的数据数量
 */
static void Protocol_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Pos)
{
	assert(huart == &wifi_uart);
	assert(parserSB!=NULL);

	uint8_t *pdata;
	uint16_t len;

	//由Buffer情况决定要搬运哪部分数据
	if(Pos == DMA_RX_BUF_LEN)	//全满
	{
		pdata = dma_rx_buf + DMA_RX_BUF_LEN/2;
		len = DMA_RX_BUF_LEN/2;
	}
	else if(Pos == DMA_RX_BUF_LEN/2)	//半满
	{
		pdata = dma_rx_buf;
		len = DMA_RX_BUF_LEN/2;
	}
	else	//空闲
	{
		pdata = (Pos > DMA_RX_BUF_LEN/2) ? (dma_rx_buf + DMA_RX_BUF_LEN/2) : dma_rx_buf;
		len = (Pos > DMA_RX_BUF_LEN/2) ? (Pos - DMA_RX_BUF_LEN/2) : Pos;

		//从头开始
		HAL_UART_AbortReceive(huart);
		HAL_UARTEx_ReceiveToIdle_DMA(&wifi_uart, dma_rx_buf, sizeof(dma_rx_buf));

	}
	//将已收到的数据送入StreamBuffer
	//剩余数据量决定了这次接收的数据位置和大小
	size_t sent = xStreamBufferSendFromISR(parserSB,pdata,len,pdFALSE);

	//StreamBuffer空间不足
	assert(sent == len);

}
